package cn.krui.project.controller.system;

import cn.krui.helper.bean.AppResult;
import cn.krui.helper.bean.DataArray;
import cn.krui.helper.bean.DataSingle;
import cn.krui.helper.bean.PublisterBean;
import cn.krui.helper.bean.SysLoginInfo;
import cn.krui.helper.db.DBHelper;
import cn.krui.helper.db.SQL;
import cn.krui.helper.db.SQL.SelectSQL;
import cn.krui.helper.pub_sub.Publisher;
import cn.krui.helper.tools.JsonUtils;
import cn.krui.helper.tools.MapUtils;
import cn.krui.helper.tools.RedisUtils;
import cn.krui.project.bean.system.sys_menu.sys_menu;
import cn.krui.project.bean.system.sys_permissions.sys_permissions;
import cn.krui.project.bean.system.sys_role.sys_role;
import cn.krui.project.bean.system.sys_user.sys_user;
import cn.krui.project.service.system.SysRoleService;
import cn.krui.project.service.system.LoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @program: project-system
 * @description: 角色模块
 * @author: zc
 * @create: 2019-10-10 16:05
 **/
@Api(tags = "管理-角色", description = "系统角色模块接口")
@RestController
@RequestMapping("/system/sysrole")
@CrossOrigin
public class SysRoleController extends SystemBaseController {
    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private DBHelper dbHelper;

    @Autowired
    private Publisher pub;

    @Value("${server.port:8080}")
    private int serverPort;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private LoginService loginService;

    private final String EQUALS_ONE = "1";
    private final String EQUALS_INIT_DEFAULT = "init_default";

    /**
     * 角色列表
     */
    @SuppressWarnings({})
    @PostMapping(value = "/getSysRoleList")
    @ApiOperation(value = "获取角色列表", httpMethod = "POST")
    public AppResult<sys_role> getSysRoleList(
            @ApiParam(value = "部门id", required = false) @RequestParam(value = "dept_id", required = false) Integer dept_id,
            @ApiParam(value = "角色名称", required = false) @RequestParam(value = "role_name", required = false) String role_name,
            @ApiParam(value = "页", required = true) @RequestParam(value = "page", required = false) Integer page,
            @ApiParam(value = "条", required = true) @RequestParam(value = "size", required = false) Integer size,
            @ApiParam(value = "拉取数据对应的用户id", required = false) @RequestParam(value = "uid", required = false) Integer uid) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        DataSingle<sys_role> sysDept = new DataSingle<>();
        sysDept.setPageIndex(page);
        sysDept.setPageSize(size);
        sys_role sysRole = new sys_role();
        sysRole.setDept_id(dept_id);
        sysRole.setRole_name(role_name);
        sysDept.setDataSingle(sysRole);
        sysDept.setExtend(uid);
        app.ok();
        app.setDataArray(sysRoleService.selectSysRoleList(sysDept));
        app.setMsg("获取成功");
        return app;
    }

    /**
     * 添加角色列表
     */
    @PostMapping(value = "/addSysRole")
    @ApiOperation(value = "添加角色列表", httpMethod = "POST")
    public AppResult<sys_role> addSysRole(
            @ApiParam(value = "部门id", required = false) @RequestParam(value = "dept_id", required = false) String dept_id,
            @ApiParam(value = "角色名称", required = true) @RequestParam(value = "role_name", required = true) String role_name,
            @ApiParam(value = "排序", required = false) @RequestParam(value = "sort", required = false) String sort,
            @ApiParam(value = "备注", required = false) @RequestParam(value = "note", required = false) String note,
            @ApiParam(value = "是否默认", required = false) @RequestParam(value = "init_default", required = false) String init_default,
            @ApiParam(value = "适用类型", required = true) @RequestParam(value = "user_type", required = false) Integer user_type) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        sys_role sysrole = new sys_role();
        sysrole.setRole_name(role_name);
        SQL.SelectSQL sql = SQL.select("id").from("qr_sys_role").where("role_name=#{role_name}")
                .where("group_id=#{group_id}").addParameter("role_name", role_name)
                .addParameter("group_id", getUser().getUid());
        List<Map<String, Object>> num = dbHelper.select(sql);
        if (num.size() > 0) {
            app.no("");
            app.setMsg("名称重复，添加失败");
            return app;
        }
        if (!StringUtils.isEmpty(note)) {
            sysrole.setNote(note);
        }
        sysrole.setStatus(1);
        sysrole.setUser_type(user_type);
        sysrole.setGroup_id(getUser().getUid());
        Integer i = sysRoleService.addSysRole(sysrole);
        if (i > 0) {
            app.ok();
            app.setMsg("添加成功");
        } else {
            app.ok("");
            app.setMsg("添加失败");
        }
        return app;
    }

    /**
     * 更改角色
     */
    @PostMapping(value = "/updateSysRole")
    @ApiOperation(value = "更改角色", httpMethod = "POST")
    public AppResult<sys_role> updateSysRole(
            @ApiParam(value = "角色名称", required = false) @RequestParam(value = "role_name", required = false) String role_name,
            @ApiParam(value = "主键id", required = true) @RequestParam(value = "id", required = false) String id,
            @ApiParam(value = "适用类型", required = true) @RequestParam(value = "user_type", required = false) Integer user_type) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        SQL.SelectSQL sql = SQL.select("id").from("qr_sys_role").where("role_name=#{role_name} and id!=#{id}")
                .where("group_id=#{group_id}").addParameter("role_name", role_name)
                .addParameter("group_id", getUser().getUid()).addParameter("id", id);
        List<Map<String, Object>> num = dbHelper.select(sql);
        if (num.size() > 0) {
            app.no("");
            app.setMsg("名称重复，更新失败");
            return app;
        }
        sys_role sysrole = new sys_role();
        sysrole.setRole_name(role_name);
        sysrole.setUser_type(user_type);
        sysrole.setId(Integer.parseInt(id));
        Integer i = sysRoleService.updateSysRole(sysrole, 0);
        if (i > 0) {
            app.ok();
            app.setMsg("更新成功");
        } else {
            app.no("");
            app.setMsg("更新失败");
        }
        return app;
    }

    /**
     * 删除系统角色
     */
    @PostMapping(value = "/deleteSysRole")
    @ApiOperation(value = "删除系统角色", httpMethod = "POST")
    public AppResult<sys_role> deleteSysRole(
            @ApiParam(value = "主键id", required = true) @RequestParam(value = "id", required = true) String id) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        SQL.SelectSQL sql = SQL.select("init_default").from("qr_sys_role").where("id=#{id}").addParameter("id", id);
        Map<String, Object> map = dbHelper.selectOne(sql);
        app.no("");
        if (EQUALS_ONE.equals(map.get(EQUALS_INIT_DEFAULT))) {
            app.setMsg("系统内置数据无法删除");
            return app;
        }
        sql = SQL.select("id").from("qr_sys_users").where("role_id=#{id}").addParameter("id", id);
        List<sys_user> list = dbHelper.select(sql, sys_user.class);
        if (list.size() > 0) {
            app.setMsg("被用户引用，无法删除");
            return app;
        }
        sys_role sysrole = new sys_role();
        sysrole.setId(Integer.parseInt(id));
        Integer i = sysRoleService.deleteSysRole(sysrole);
        if (i > 0) {
            app.ok();
            app.setMsg("删除成功");
        } else {
            app.setMsg("删除失败");
        }
        return app;
    }

    /**
     * 菜单授权
     */
    @PostMapping(value = "/menuAuthorization")
    @ApiOperation(value = "菜单授权", httpMethod = "POST")
    public AppResult<sys_role> menuAuthorization(
            @ApiParam(value = "主键id", required = true) @RequestParam(value = "id", required = true) String id,
            @ApiParam(value = "权限id", required = true) @RequestParam(value = "role_menu", required = true) String role_menu,
            @ApiParam(value = "按钮权限", required = true) @RequestParam(value = "role_permissions", required = true) String role_permissions) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        sys_role sysrole = new sys_role();
        /**************** 检查权限 ********************************/
        String[] roleMenuArray = role_menu.split(",");
        Set<String> roleMenus = new HashSet<>(100);
        for (String str : getUser().getRole_menu().split(",")) {
            roleMenus.add(str);
        }
        List<String> roleMenuArrayCopy = new ArrayList<>(100);
        for (String str : roleMenuArray) {
            if (getUser().getUid() == getUser().getGroup_id()) {
                // 超管特权
                roleMenuArrayCopy.add(str);
                continue;
            }
            if (roleMenus.contains(str)) {
                roleMenuArrayCopy.add(str);
                roleMenus.remove(str);
            }
        }
        /***********************************************************************/
        sysrole.setRole_menu(String.join(",", roleMenuArrayCopy));
        sysrole.setId(Integer.parseInt(id));
        Integer i = sysRoleService.updateSysRole(sysrole, 1);
        if (i > 0) {
            app.ok();
            app.setMsg("授权成功");
            //更新角色权限
            Map<String,Object> upp = dbHelper.selectOne("role_permissions", "qr_sys_role", String.format("id=%s",id), null);
            String perstr = getPermissions(String.join(",", roleMenuArrayCopy),upp.get("role_permissions").toString());
            sysrole.setRole_permissions(perstr);
            i =  sysRoleService.updateSysRole(sysrole, 2);
            if(i<=0){
                app.no("授权失败");
            }
            // 发布角色删除消息
            PublisterBean<sys_role> data = new PublisterBean<sys_role>("role_pers_set");
            data.setData(sysrole);
            data.setExecUrl(String.format("http://127.0.0.1:%s%s", serverPort, "/system/sysrole/afteRolePersSet"));
            pub.pub("system_channel", data);
        } else {
            app.no("");
            app.setMsg("授权失败");
        }
        return app;
    }

    /**
     * 权限授权
     */
    @PostMapping(value = "/permissionsAuthorization")
    @ApiOperation(value = "权限授权", httpMethod = "POST")
    public AppResult<sys_role> permissionsAuthorization(
            @ApiParam(value = "主键id", required = true) @RequestParam(value = "id", required = true) String id,
            @ApiParam(value = "菜单权限", required = true) @RequestParam(value = "role_menu", required = true) String role_menu,
            @ApiParam(value = "按钮权限", required = true) @RequestParam(value = "role_permissions", required = true) String role_permission) {
        AppResult<sys_role> app = new AppResult<sys_role>();
        sys_role sysrole = new sys_role();

        /**************** 检查权限 ********************************/
        String[] roleMenuArray = role_menu.split(",");
        Set<String> roleMenus = new HashSet<>();
        for (String str : getUser().getRole_menu().split(",")) {
            roleMenus.add(str);
        }
        List<String> roleMenuArrayCopy = new ArrayList<>(100);
        for (String str : roleMenuArray) {
            if (getUser().getUid() == getUser().getGroup_id()) {
                // 超管特权
                roleMenuArrayCopy.add(str);
                continue;
            }
            if (roleMenus.contains(str)) {
                roleMenuArrayCopy.add(str);
                roleMenus.remove(str);
            }
        }
        String[] rolePermissionsArray = role_permission.split(",");
        Set<String> rolePermissions = new HashSet<>();
        for (String str : getUser().getRole_permissions().split(",")) {
            rolePermissions.add(str);
        }
        List<String> rolePermissionsArrayCopy = new ArrayList<>(100);
        for (String str : rolePermissionsArray) {
            if (getUser().getUid() == getUser().getGroup_id()) {
                // 超管特权
                rolePermissionsArrayCopy.add(str);
                continue;
            }
            if (rolePermissions.contains(str)) {
                rolePermissionsArrayCopy.add(str);
                rolePermissions.remove(str);
            }
        }
        /***********************************************************************/
        sysrole.setRole_permissions(
                getPermissions(String.join(",", roleMenuArrayCopy), String.join(",", rolePermissionsArrayCopy)));
        sysrole.setId(Integer.parseInt(id));
        Integer i = sysRoleService.updateSysRole(sysrole, 2);
        if (i > 0) {
            app.ok();
            app.setMsg("授权成功");
            // 发布角色删除消息
            PublisterBean<sys_role> data = new PublisterBean<sys_role>("role_pers_set");
            data.setData(sysrole);
            data.setExecUrl(String.format("http://127.0.0.1:%s%s", serverPort, "/system/sysrole/afteRolePersSet"));
            pub.pub("system_channel", data);
        } else {
            app.no("");
            app.setMsg("授权失败");
        }
        return app;
    }

    public String getPermissions(String roleMenu, String rolePermissions) {
        // if (getUser().getUid() == getUser().getGroup_id()) {
        //     return dbHelper.selectOne("GROUP_CONCAT(permissions_code) pcode", "qr_sys_permissions", "", null).get("pcode").toString();
        // }
        SQL.SelectSQL sql = SQL.select("p.permissions_code,p.status").from("qr_sys_permissions p")
                .leftJoin("qr_sys_menu m", "m.id = p.menu_id")
                .where(" LOCATE(CONCAT(',',m.code,','),CONCAT(',',#{role_menu},','))>0")
                .addParameter("role_menu", roleMenu);
        // 获取所有列表项数据
        List<sys_permissions> pList = dbHelper.select(sql, sys_permissions.class);
        String permissions = "," + rolePermissions + ",";
        Set<String> set = new HashSet<>(100);
        for (sys_permissions p : pList) {
            if (set.contains(p.getPermissions_code())) {
                continue;
            }
            if(p.getStatus()==0){
                set.add(p.getPermissions_code());continue;
            }
            if (permissions.indexOf("," + p.getPermissions_code() + ",") > -1) {
                set.add(p.getPermissions_code());
            }
        }
        return String.join(",", set);
    }

    /**
     * 权限按钮列表
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @PostMapping(value = "/getSysPermissionsList")
    @ApiOperation(value = "权限按钮列表", httpMethod = "POST")
    public AppResult<sys_permissions> getSysPermissionsList(
            @ApiParam(value = "菜单列表", required = true) @RequestParam(value = "role_menu", required = true) String role_menu) {
        AppResult<sys_permissions> app = new AppResult<sys_permissions>();
        SQL.SelectSQL sql = SQL.select("m.*").from("qr_sys_menu m").leftJoin("qr_sys_permissions p", "p.menu_id=m.id")
                .where(" LOCATE(CONCAT(',',m.code,','),CONCAT(',',#{role_menu},','))>0 and p.id is not null")
                .groupBy("m.id").orderBy("m.id ASC").addParameter("role_menu", role_menu);
        List<sys_menu> menuList = dbHelper.select(sql, sys_menu.class);
        /*************** 排除无权限菜单****************** */
        List<sys_menu> copyMenuList = new ArrayList<>();
        Set<String> roleMenus = new HashSet<>();
        for (String str : getUser().getRole_menu().split(",")) {
            roleMenus.add(str);
        }
        for (sys_menu sysMenu : menuList) {
            if (getUser().getUid() == getUser().getGroup_id()) {
                // 超管特权
                copyMenuList.add(sysMenu);
                continue;
            }
            if (roleMenus.contains(sysMenu.getCode())) {
                copyMenuList.add(sysMenu);
                roleMenus.remove(sysMenu.getCode());
            }
        }
        menuList.clear();
        /********************************* */
        List<sys_permissions> pList = new ArrayList<>();
        SQL.SelectSQL permissionSql = SQL.select("*").from("qr_sys_permissions").where("status!=0")
                .orderBy("sort desc");
        List<sys_permissions> childList = dbHelper.select(permissionSql, sys_permissions.class);
        /**************** 过滤权限********************** */
        List<sys_permissions> copyPermissionList = new ArrayList<>();
        Set<String> rolePermissions = new HashSet<>(100);
        for (String str : getUser().getRole_permissions().split(",")) {
            rolePermissions.add(str);
        }
        for (sys_permissions sysPermissions : childList) {
            if (getUser().getUid() == getUser().getGroup_id()) {
                // 超管特权
                copyPermissionList.add(sysPermissions);
            }
            else{
                if (rolePermissions.contains(sysPermissions.getPermissions_code())) {
                    copyPermissionList.add(sysPermissions);
                    rolePermissions.remove(sysPermissions.getPermissions_code());
                }
            }
        }
        menuList.clear();
        /************************************** */
        // 循环递归获取子解点数据
        for (sys_menu nav : copyMenuList) {
            boolean flag = false;
            List<sys_permissions> pmList = new ArrayList<>();
            sys_permissions sysPermissions = new sys_permissions();
            for (sys_permissions p : copyPermissionList) {
                if (nav.getId().equals(p.getMenu_id())) {
                    p.setSort(0);
                    pmList.add(p);
                    sysPermissions.setPermissions_code(p.getPermissions_code());
                    flag = true;
                }
            }
            if (flag) {
                sysPermissions.setPermissions_name(nav.getMenu_name());
                sysPermissions.setChildren(pmList);
                pList.add(sysPermissions);
            }
        }
        app.ok();
        DataArray list = new DataArray<sys_permissions>();
        list.setDataList(pList);
        list.setDataCount(menuList.size());
        app.setDataArray(list);
        app.setMsg("获取成功");
        return app;
    }

    /**
     * 获取子节点
     * 
     * @param id      父节点id
     * @param allMenu 所有菜单列表
     * @return 每个根节点下，所有子菜单列表
     */
    public List<sys_permissions> getChild(Integer id) {
        List<sys_permissions> list = new ArrayList<sys_permissions>();
        // 子菜单
        SelectSQL sql = SQL.select("*").from("qr_sys_permissions").where("menu_id=#{id}").orderBy("sort desc")
                .addParameter("id", id);
        List<sys_permissions> childList = dbHelper.select(sql, sys_permissions.class);
        for (sys_permissions nav : childList) {
            nav.setChildren(this.getChild(nav.getId()));
            list.add(nav);
        }

        return list;
    }

    /**
     * 权限变更后触发事件
     */
    @PostMapping(value = "/afteRolePersSet")
    @ApiOperation(value = "权限变更后触发", httpMethod = "POST")
    public AppResult<String> afteRolePersSet() {
        AppResult<String> app = new AppResult<String>();

        String key = "";
        Map<String, Object> whereMap = new HashMap<>(100);
        while (key != null) {
            //注意_0是这类消息的一种消费方式，用于处理单消息多订阅处理，队列做了同模块消息去重
            key = redisUtils.lLeftPop(String.format("pub:%s:%s_list_0", "system_channel", "role_pers_set"));
            if (!StringUtils.isEmpty(key)) {
                sys_role sysRole = JsonUtils.toObject(key, sys_role.class);
                if (sysRole != null && sysRole.getId() != null) {
                    SelectSQL sql = SQL.select("qsu.id,qsu.token,qsu.user_name,qsu.group_id,qsu.role_id")
                            .from("qr_sys_users qsu").innerJoin("qr_sys_role", "qsr", "qsu.role_id = qsr.id")
                            .where("qsu.role_id = #{role_id} AND qsu.token IS NOT NULL ")
                            .addParameter("role_id", sysRole.getId());
                    List<Map<String, Object>> lst = dbHelper.select(sql);
                    for (Map<String, Object> map : lst) {
                        String usrToken = String.format("login_token:%s", MapUtils.getString(map, "token"));
                        SysLoginInfo sysLoginInfo = new SysLoginInfo();
                        sysLoginInfo.setCreate_time(new Date());
                        sysLoginInfo.setUser_type("1");
                        sysLoginInfo.setToken(usrToken);
                        sysLoginInfo.setUid(MapUtils.getInt(map, "id"));
                        sysLoginInfo.setRole_menu("");
                        sysLoginInfo.setRole_permissions("");
                        sysLoginInfo.setUser_name(MapUtils.getString(map, "user_name"));
                        sysLoginInfo.setGroup_id(MapUtils.getInt(map, "group_id"));
                        whereMap.clear();
                        whereMap.put("role_id", MapUtils.getInt(map, "role_id"));
                        whereMap.put("group_id", MapUtils.getInt(map, "group_id"));
                        Map<String, Object> roleMenuPermission = dbHelper.selectOne(
                                "qsr.role_menu,qsr.role_permissions", "qr_sys_role qsr",
                                "qsr.id=#{role_id} and qsr.group_id=#{group_id}", whereMap);
                        if (roleMenuPermission.size() > 0) {
                            sysLoginInfo.setRole_menu(roleMenuPermission.get("role_menu").toString());
                            sysLoginInfo.setRole_permissions(roleMenuPermission.get("role_permissions").toString());
                            sysLoginInfo.setRole_permissions_map(loginService.rolePermissionsToMap(sysLoginInfo.getRole_permissions()));
                        }
                        redisUtils.set(usrToken, JsonUtils.toJson(sysLoginInfo));
                    }
                }
            }
        }
        app.ok("afteRolePersSet处理完成");
        return app;
    }

}
